/* Copyright (c) 2009-2010, Sean A.O. Harney <sharney3@gmail.com> */

#include "omf.h"


/* prototypes */
ASL_NODE_P _new_stmt(STMT_TYPE type);
ASL_NODE_P _new_stmt_fuzzdata(void);
ASL_NODE_P _new_stmt_target(void);
ASL_NODE_P _new_stmt_start(void);
ASL_NODE_P _new_stmt_flag(void);
ASL_NODE_P _new_stmt_send(void);
ASL_NODE_P _new_stmt_expect(void);
ASL_NODE_P _new_stmt_print(void);
ASL_NODE_P _new_stmt_include(void);
ASL_NODE_P _new_stmt_shell(void);
ASL_NODE_P _new_stmt_repeat(void);
ASL_NODE_P _new_stmt_if(void);
ASL_NODE_P _new_stmt_return(void);
ASL_NODE_P _new_stmt_sleep(void);
ASL_NODE_P _new_stmt_expr_stmt(void);
ASL_NODE_P _new_stmt_var_decl(void);

extern int yylineno;


char *stmt_type_to_str(STMT_TYPE type)
{
    switch (type)
      {
      case STMT_FUZZDATA:
	  return "STMT_FUZZDATA";
      case STMT_TARGET:
	  return "STMT_TARGET";
      case STMT_START:
	  return "STMT_START";
      case STMT_FLAG:
	  return "STMT_FLAG";
      case STMT_SEND:
	  return "STMT_SEND";
      case STMT_EXPECT:
	  return "STMT_EXPECT";
      case STMT_PRINT:
	  return "STMT_PRINT";
      case STMT_INCLUDE:
	  return "STMT_INCLUDE";
      case STMT_SHELL:
	  return "STMT_SHELL";
      case STMT_REPEAT:
	  return "STMT_REPEAT";
      case STMT_IF:
	  return "STMT_IF";
      case STMT_RETURN:
	  return "STMT_RETURN";
      case STMT_SLEEP:
	  return "STMT_SLEEP";
      case STMT_EXPR_STMT:
	  return "STMT_EXPR_STMT";
      case STMT_VAR_DECL:
	  return "STMT_VAR_DECL";
      default:
	  return "unknown";
      }
}


ASL_NODE_P new_stmt_fuzzdata_pattern(char *pattern, size_t pattern_maxlen)
{
    ASL_NODE_P stmt = _new_stmt_fuzzdata();
    stmt->params.stmt_fuzzdata.pattern = pattern;
    stmt->params.stmt_fuzzdata.pattern_maxlen = pattern_maxlen;
    return stmt;
}

ASL_NODE_P new_stmt_fuzzdata_file(char *file)
{
    ASL_NODE_P stmt = _new_stmt_fuzzdata();
    stmt->params.stmt_fuzzdata.file = file;
    return stmt;
}

ASL_NODE_P new_stmt_fuzzdata_random(size_t lb, size_t ub)
{
    ASL_NODE_P stmt = _new_stmt_fuzzdata();
    stmt->params.stmt_fuzzdata.random = true;
    stmt->params.stmt_fuzzdata.random_length_lb = lb;
    stmt->params.stmt_fuzzdata.random_length_ub = ub;
    return stmt;
}

ASL_NODE_P new_stmt_target_dl(LLIST_P args, int ind_doubledollar,
			      char *libfname, char *symbol)
{
    ASL_NODE_P stmt = _new_stmt_target();
    stmt->params.stmt_target.dl = true;
    stmt->params.stmt_target.dl_args = args;
    stmt->params.stmt_target.dl_libfname = libfname;
    stmt->params.stmt_target.dl_symbol = symbol;
    stmt->params.stmt_target.dl_ind_doubledollar = ind_doubledollar;
    return stmt;
}

ASL_NODE_P new_stmt_target_command(LLIST_P argv, int ind_doubledollar,
				   bool fuzz_stdin)
{
    ASL_NODE_P stmt = _new_stmt_target();
    stmt->params.stmt_target.command = true;
    stmt->params.stmt_target.command_argv = argv;
    stmt->params.stmt_target.command_stdin = fuzz_stdin;
    stmt->params.stmt_target.command_ind_doubledollar = ind_doubledollar;
    return stmt;
}


ASL_NODE_P new_stmt_target_socket(char *host, int port, int socket_type)
{
    ASL_NODE_P stmt = _new_stmt_target();
    stmt->params.stmt_target.socket = true;
    stmt->params.stmt_target.socket_host = host;
    stmt->params.stmt_target.socket_port = port;
    stmt->params.stmt_target.socket_type = socket_type;
    return stmt;
}

ASL_NODE_P new_stmt_start(int start_arg)
{
    ASL_NODE_P stmt = _new_stmt_start();
    stmt->params.stmt_start.start_arg = start_arg;
    return stmt;
}

ASL_NODE_P new_stmt_flag_termination_exit(int status)
{
    ASL_NODE_P stmt = _new_stmt_flag();
    stmt->params.stmt_flag.termination_exit = true;
    stmt->params.stmt_flag.val = status;
    return stmt;
}

ASL_NODE_P new_stmt_flag_termination_signal(unsigned int signal)
{
    ASL_NODE_P stmt = _new_stmt_flag();
    stmt->params.stmt_flag.termination_exit = true;
    stmt->params.stmt_flag.val = signal;
    return stmt;
}

ASL_NODE_P new_stmt_flag_termination_exit_any(void)
{
    ASL_NODE_P stmt = _new_stmt_flag();
    stmt->params.stmt_flag.termination_exit_any = true;
    return stmt;
}

ASL_NODE_P new_stmt_flag_termination_signal_any(void)
{
    ASL_NODE_P stmt = _new_stmt_flag();
    stmt->params.stmt_flag.termination_signal_any = true;
    return stmt;
}

ASL_NODE_P new_stmt_flag_termination_any(void)
{
    ASL_NODE_P stmt = _new_stmt_flag();
    stmt->params.stmt_flag.termination_any = true;
    return stmt;
}

ASL_NODE_P new_stmt_send(uint8_t * buf, size_t len)
{
    ASL_NODE_P stmt = _new_stmt_send();
    stmt->params.stmt_send.buf = buf;
    stmt->params.stmt_send.len = len;
    return stmt;
}

ASL_NODE_P new_stmt_send_str(char *str)
{
    return new_stmt_send((uint8_t *) str, strlen(str) + 1);	/* +1 for NUL char */
}

ASL_NODE_P new_stmt_send_doubledollar(void)
{
    return NULL;		//for now
}

ASL_NODE_P new_stmt_expect(void)
{
    return NULL;		//for now
}

ASL_NODE_P new_stmt_print(EXPR_P expr)
{
    ASL_NODE_P stmt = _new_stmt_print();
    stmt->params.stmt_print.expr = expr;
    return stmt;
}

ASL_NODE_P new_stmt_include(char *file)
{
    ASL_NODE_P stmt = _new_stmt_include();
    stmt->params.stmt_include.file = file;
    return stmt;
}

ASL_NODE_P new_stmt_shell(char *command_str)
{
    ASL_NODE_P stmt = _new_stmt_shell();
    stmt->params.stmt_shell.command_str = command_str;
    return stmt;
}

ASL_NODE_P new_stmt_repeat(EXPR_P expr, ASL_NODE_P stmt)
{
    ASL_NODE_P ret_stmt = _new_stmt_repeat();
    ret_stmt->params.stmt_repeat.expr = expr;
    ret_stmt->params.stmt_repeat.stmt = stmt;
    return ret_stmt;
}

ASL_NODE_P new_stmt_if(EXPR_P expr, ASL_NODE_P stmt)
{
    ASL_NODE_P ret_stmt = _new_stmt_if();
    ret_stmt->params.stmt_if.expr = expr;
    ret_stmt->params.stmt_if.stmt = stmt;
    return ret_stmt;
}

ASL_NODE_P new_stmt_return(EXPR_P expr)
{
    ASL_NODE_P ret_stmt = _new_stmt_return();
    ret_stmt->params.stmt_return.expr = expr;
    return ret_stmt;
}

ASL_NODE_P new_stmt_sleep(int secs)
{
    ASL_NODE_P stmt = _new_stmt_sleep();
    stmt->params.stmt_sleep.secs = secs;
    return stmt;
}

ASL_NODE_P new_stmt_expr_stmt(EXPR_P expr)
{
    ASL_NODE_P stmt = _new_stmt_expr_stmt();
    stmt->params.stmt_expr_stmt.expr = expr;
    return stmt;
}

//assumes EXPR_P is of type EXPR_ASSIGNMENT
ASL_NODE_P new_stmt_var_decl_initialized(EXPR_P assignment_expr)
{
    ASL_NODE_P stmt = _new_stmt_var_decl();
    stmt->params.stmt_var_decl.initialized = true;
    stmt->params.stmt_var_decl.u.initialized.assignment_expr =
	assignment_expr;
    return stmt;
}

//uninitialized
ASL_NODE_P new_stmt_var_decl(char *varname)
{
    ASL_NODE_P stmt = _new_stmt_var_decl();
    stmt->params.stmt_var_decl.initialized = false;
    stmt->params.stmt_var_decl.u.uninitialized.varname = varname;
    return stmt;
}


ASL_NODE_P _new_stmt(STMT_TYPE type)
{
    ASL_NODE_P stmt = checked_malloc(sizeof(struct st_asl_node));

    stmt->type = type;
    stmt->lineno = yylineno;
    stmt->filename = glob.parser_current_filename;
    //TODO: strdup may be necessary.
    return stmt;
}

ASL_NODE_P _new_stmt_fuzzdata(void)
{
    ASL_NODE_P stmt = _new_stmt(STMT_FUZZDATA);
    stmt->params.stmt_fuzzdata.pattern = NULL;
    stmt->params.stmt_fuzzdata.pattern_maxlen = 0;
    stmt->params.stmt_fuzzdata.file = NULL;
    stmt->params.stmt_fuzzdata.random = 0;
    stmt->params.stmt_fuzzdata.random = 0;
    stmt->params.stmt_fuzzdata.random_length_lb = 0;
    stmt->params.stmt_fuzzdata.random_length_ub = 0;
    return stmt;
}

ASL_NODE_P _new_stmt_target(void)
{
    ASL_NODE_P stmt = _new_stmt(STMT_TARGET);

    stmt->params.stmt_target.command = false;
    stmt->params.stmt_target.command_argv = NULL;
    stmt->params.stmt_target.command_stdin = false;
    stmt->params.stmt_target.command_ind_doubledollar = -1;

    stmt->params.stmt_target.dl = false;
    stmt->params.stmt_target.dl_libfname = NULL;
    stmt->params.stmt_target.dl_symbol = NULL;
    stmt->params.stmt_target.dl_args = NULL;
    stmt->params.stmt_target.dl_ind_doubledollar = -1;

    stmt->params.stmt_target.socket = false;
    stmt->params.stmt_target.socket_host = NULL;
    stmt->params.stmt_target.socket_port = 0;
    stmt->params.stmt_target.socket_type = -1;

    return stmt;
}

ASL_NODE_P _new_stmt_start(void)
{
    ASL_NODE_P stmt = _new_stmt(STMT_START);
    stmt->params.stmt_start.start_arg = -1;
    return stmt;
}

ASL_NODE_P _new_stmt_flag(void)
{
    ASL_NODE_P stmt = _new_stmt(STMT_FLAG);
    stmt->params.stmt_flag.termination_any = false;
    stmt->params.stmt_flag.termination_signal_any = false;
    stmt->params.stmt_flag.termination_exit_any = false;
    stmt->params.stmt_flag.termination_signal = false;
    stmt->params.stmt_flag.termination_exit = false;
    stmt->params.stmt_flag.val = 0;
    return stmt;
}

ASL_NODE_P _new_stmt_send(void)
{
    ASL_NODE_P stmt = _new_stmt(STMT_SEND);
    stmt->params.stmt_send.buf = NULL;
    stmt->params.stmt_send.len = 0;
    return stmt;
}

ASL_NODE_P _new_stmt_expect(void)
{
    ASL_NODE_P stmt = _new_stmt(STMT_SEND);
    return stmt;
}

ASL_NODE_P _new_stmt_print(void)
{
    ASL_NODE_P stmt = _new_stmt(STMT_PRINT);
    stmt->params.stmt_print.expr = NULL;
    return stmt;
}

ASL_NODE_P _new_stmt_include(void)
{
    ASL_NODE_P stmt = _new_stmt(STMT_INCLUDE);
    stmt->params.stmt_include.file = NULL;
    return stmt;
}

ASL_NODE_P _new_stmt_shell(void)
{
    ASL_NODE_P stmt = _new_stmt(STMT_SHELL);
    stmt->params.stmt_shell.command_str = NULL;
    return stmt;
}

ASL_NODE_P _new_stmt_repeat(void)
{
    ASL_NODE_P stmt = _new_stmt(STMT_REPEAT);
    stmt->params.stmt_repeat.expr = NULL;
    stmt->params.stmt_repeat.stmt = NULL;
    return stmt;
}

ASL_NODE_P _new_stmt_if(void)
{
    ASL_NODE_P stmt = _new_stmt(STMT_IF);
    stmt->params.stmt_if.expr = NULL;
    stmt->params.stmt_if.stmt = NULL;
    return stmt;
}

ASL_NODE_P _new_stmt_return(void)
{
    ASL_NODE_P stmt = _new_stmt(STMT_RETURN);
    stmt->params.stmt_return.expr = NULL;
    return stmt;
}

ASL_NODE_P _new_stmt_sleep(void)
{
    ASL_NODE_P stmt = _new_stmt(STMT_SLEEP);
    stmt->params.stmt_sleep.secs = 0;
    return stmt;
}

ASL_NODE_P _new_stmt_expr_stmt(void)
{
    ASL_NODE_P stmt = _new_stmt(STMT_EXPR_STMT);
    stmt->params.stmt_expr_stmt.expr = NULL;
    return stmt;
}

ASL_NODE_P _new_stmt_var_decl(void)
{
    ASL_NODE_P stmt = _new_stmt(STMT_VAR_DECL);
    memset(&(stmt->params.stmt_var_decl), 0,
	   sizeof(struct st_stmt_var_decl));
    stmt->params.stmt_var_decl.filename = stmt->filename;	//same filename,needed for vardecl process-time
    return stmt;
}
